#coding: utf-8
from collections import deque

from time import time
import traceback

from threading import Thread
from threading import Event
from threading import Lock
from threading import Condition


class Storage:
	def __init__(self):
		self.__queue=deque()
	def _put(self,item):
		self.__queue.append(item)
	def _get(self):
		return self.__queue.popleft()
	def _size(self):
		return len(self.__queue)

class Kill(Exception):pass

class ThreadPool(object,Storage):
	__kill=object()
	threadFactory=Thread
	def __init__(self,maxTh=3,orderlyTh=0,lifeTime=0,maxSize=0):
		Storage.__init__(self)
		assert maxTh >= 0 and orderlyTh >=0 , u"the number of threads should be a positive number"
		assert maxTh>=orderlyTh, u"Duty flows must be less than the maximum number of"
		self._maxTh             = maxTh
		self._orderlyTh         = orderlyTh
		self.__wait             = lifeTime and self.__deadlineExpectation(lifeTime) or self.__simplyExpectation
		self._maxSize           = maxSize
		self._stopped           = False
		self._mutex             = Lock()
		self._freeze            = Condition(self._mutex)
		self._eventAboutEmpty   = Event()
		self._eventAboutStopped = Event()
		self._threadCurrent     = 0
		self._unfinishedTask    = 0
		self.__genThreads       = 0
		self.__receivedTasks    = 0
		if self._orderlyTh:
			for x in xrange(self._orderlyTh):
				self.__startWorker()
	@property
	def threadCurrent(self):
		return self._threadCurrent
	@property
	def unfinishedTask(self):
		return self._unfinishedTask
	def start(self,item):
		if self._stopped:
				return
		with self._mutex:
			if self._eventAboutEmpty.is_set():
				self._eventAboutEmpty.clear()
			self._put(item)
			self._unfinishedTask+=1
			self._freeze.notify()
			self.__receivedTasks+=1
		if (self._maxTh and self.unfinishedTask > self._threadCurrent and self._threadCurrent < self._maxTh or
			not self._maxTh and self.unfinishedTask > self._threadCurrent) :
				self.__startWorker()
	def __simplyExpectation(self):
		while self._size()==0:
			if self._stopped :
				raise Kill
			self._freeze.wait()
	def __deadlineExpectation(self,waitTime):
		def wait():
			timeleft=time()+waitTime
			while self._size()==0:
				if timeleft<=time() and self.__conviction():
					raise Kill
				elif self._stopped:
					raise Kill
				self._freeze.wait(waitTime)
		return wait
	def __conviction(self):
		if self._threadCurrent>self._orderlyTh:
			return True
		return False
	def __startWorker(self):
		if self._eventAboutStopped.is_set():
			self._eventAboutStopped.clear()
		self._threadCurrent+=1
		self.__genThreads+=1
		newTh=self.threadFactory(target=self._performer,name="ThreadPool-{id}-{ord}".format(id=id(self),ord=self._threadCurrent))
		newTh.daemon = True
		newTh.start()
	def _performer(self):
		while True:
			try:
				with self._mutex:
					self.__wait()
					task=self._get()
				if task is self.__kill:
					raise Kill
				try:
					task()
				finally:
					self._unfinishedTask-=1
					if self._unfinishedTask==0:
						self._eventAboutEmpty.set()
			except Kill:
				break
			except Exception:
				print traceback.format_exc()
		self._threadCurrent-=1
		if self._threadCurrent==0:
			self._eventAboutStopped.set()
	def waitT(self):
		self._eventAboutEmpty.wait()
	def waitP(self):
		self._eventAboutStopped.wait()
	def stopAll(self):
		with self._mutex:
			self._stopped=True
			self._freeze.notifyAll()
	def stopSomeThread(self):
		with self._mutex:
			assert self.__conviction(),u"unstoppable flow of duty"
			self._put(self.__kill)
			self._freeze.notify()
	def __getstat__(self):
		return type("state",(),{'currentThread':self.threadCurrent,
			'currentTasks':self._unfinishedTask,
			'generatedThreads':self.__genThreads,
			'receivedTasks':self.__receivedTasks,
			'nowInQueue':self._size()})



